#include "login.h"
#include "log.h"
#include "md5.h"
#include "des.h"
#include "util.h"
#include "cjson.h"
#include "kmysql.h"
#include "base64.h"
#include "config.h"
#include "redis_api.h"
#include <fcgi_stdio.h>
#include <mysql/mysql.h>

int GetLoginInfo(char *login_buf, char *username, char *pwd)
{
    if (login_buf == NULL || username == NULL || pwd == NULL)
    {
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "input param error\n");
        return -1;
    }

    int ret = 0;

    cJSON *json = cJSON_Parse(login_buf);
    do
    {
        if (json == NULL)
        {
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "cJSON_Parse error\n");
            ret = -1;
            break;
        }

        cJSON *jsonUser = cJSON_GetObjectItem(json, "userName");
        if (jsonUser == NULL)
        {
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "cJSON_GetObjectItem error\n");
            ret = -1;
            break;
        }

        cJSON *jsonPWD = cJSON_GetObjectItem(json, "pwd");
        if (jsonPWD == NULL)
        {
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "cJSON_GetObjectItem error\n");
            ret = -1;
            break;
        }

        strcpy(username, jsonUser->valuestring);
        strcpy(pwd, jsonPWD->valuestring);

    } while (0);

    if (json != NULL)
    {
        cJSON_Delete(json);
        json = NULL;
    }
    return ret;
}

int CheckUserPasswd(char *username, char *passwd)
{
    LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "CheckUserPasswd\n");
    if (username == NULL || passwd == NULL)
    {
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "input param error\n");
        return -1;
    }

    int ret = 0;
    char sqlCmd[SQL_MAX_LEN] = {0};
    char mysqlUser[SQL_CONFIG_BUFFER_SIZE] = {0};
    char mysqlPwd[SQL_CONFIG_BUFFER_SIZE] = {0};
    char mysqlDB[SQL_CONFIG_BUFFER_SIZE] = {0};
    GetMysqlInfo(mysqlUser, mysqlPwd, mysqlDB);
    LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "mysqlUser: %s, mysqlPwd: %s, mysqlDB: %s\n", mysqlUser, mysqlPwd, mysqlDB);

    MYSQL *conn = MysqlConn(mysqlUser, mysqlPwd, mysqlDB);
    if (conn == NULL)
    {
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "msql_conn error\n");
        return -1;
    }

    // 设置数据库编码
    mysql_query(conn, "set names utf8");

    sprintf(sqlCmd, "select * from user_info where user_name='%s'", username);

    char out[SQL_PWD_LEN] = {0};
    ProcessResultOne(conn, sqlCmd, out, 3);
    if (strcmp(out, passwd) == 0)
        ret = 0;
    else
        ret = -1;

    mysql_close(conn);

    return ret;
}

int SetToken(char *username, char *token)
{
    if (username == NULL || token == NULL)
    {
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "input param error\n");
        return -1;
    }

    int ret = 0;
    char redisIp[REDIS_IP_LEN] = {0};
    char redisPort[REDIS_PORT_LEN] = {0};
    GetConfigValue(CONFIG_PATH, "redis", "ip", redisIp);
    GetConfigValue(CONFIG_PATH, "redis", "port", redisPort);
    LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "redisIp: %s, redisPort: %s\n", redisIp, redisPort);
    redisContext *conn = rop_connectdb_nopwd(redisIp, redisPort);

    if (conn == NULL)
    {
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "rop_connectdb_nopwd error\n");
        return -1;
    }

    do
    {
        // 生成token
        int randNum[4] = {0};
        // 生成随机数  时间种子
        srand((uint32_t)time(NULL));
        for (int i = 0; i < 4; i++)
            randNum[i] = rand() % 1000;

        char tmp[1024] = {0};
        sprintf(tmp, "%d%d%d%d", randNum[0], randNum[1], randNum[2], randNum[3]);
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "tmp: %s\n", tmp);

        // des加密
        char encTmp[1024 * 2] = {0};
        int encLen = 0;
        ret = DesEnc((unsigned char *)tmp, strlen(tmp), (unsigned char *)encTmp, &encLen);
        if (ret != 0)
        {
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "DesEnc error\n");
            ret = -1;
            break;
        }

        // base64编码
        char base64[1024 * 3] = {0};
        base64_encode((const unsigned char *)encTmp, encLen, base64);
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "base64: %s\n", base64);

        // md5
        MD5_CTX md5;
        MD5Init(&md5);
        unsigned char decrypt[MD5_LEN] = {0};
        MD5Update(&md5, (unsigned char *)base64, strlen(base64));
        MD5Final(&md5, decrypt);
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "md5: %s\n", decrypt);

        for (int i = 0; i < MD5_LEN; i++)
            sprintf(token + i * 2, "%02x", decrypt[i]);
        LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "token: %s\n", token);

        // 存入redis
        ret = rop_setex_string(conn, username, TOKEN_TIMEOUT, token);
        if (ret != 0)
        {
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "rop_setex_string error\n");
            ret = -1;
            break;
        }
    } while (0);

    if (conn)
        rop_disconnect(conn);

    return ret;
}

void ReturnLoginStatus(char *statusCode, char *token)
{
    if (NULL == statusCode || NULL == token)
        return;

    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "code", statusCode);
    cJSON_AddStringToObject(root, "token", token);
    char *out = cJSON_Print(root);
    if (out != NULL)
    {
        printf(out);
        free(out);
    }
    cJSON_Delete(root);
}

int main()
{
    // 等待用户连接
    while (FCGI_Accept() >= 0)
    {
        char *contentLen = getenv("CONTENT_LENGTH");
        int len = 0;
        char token[TOKEN_LEN] = {0};

        printf("Content-type: text/html\r\n\r\n");
        if (NULL == contentLen)
            len = 0;
        else
            len = atoi(contentLen);

        if (len <= 0)
        {
            printf("No data from standard input.<p>\n");
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "len = 0, No data from standard input\n");
        }
        else
        {
            // 获取登录信息
            char buff[4 * 1024] = "";
            int ret = 0;
            // 从标准流读取数据
            ret = fread(buff, 1, len, stdin);
            if (ret == 0)
            {
                LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "fread(buff, 1, len, stdin) error\n");
                continue;
            }
            LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "buff: %s\n", buff);

            char username[128] = {0};
            char pwd[128] = {0};
            ret = GetLoginInfo(buff, username, pwd);
            if (ret != 0)
            {
                LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "GetLoginInfo error\n");
                ReturnLoginStatus("001", "fail");
                continue;
            }

            // 检查用户名和密码
            ret = CheckUserPasswd(username, pwd);
            if (ret != 0)
            {
                LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "CheckUserPasswd error\n");
                ReturnLoginStatus("001", "fail");
                continue;
            }
            else
            {
                // 设置token
                ret = SetToken(username, token);
                if (ret != 0)
                    LOG(LOGIN_LOG_MODULE, LOGIN_LOG_PROC, "Redis SetToken error\n");

                ReturnLoginStatus("000", token);
            }
        }
    }

    return 0;
}